This example mirrors additive.mesh.html.

In [1]:
from pathlib import Path

from ipyniivue import download_dataset

BASE_API_URL = "https://niivue.com/demos/images"
DATA_FOLDER = Path("images")

# Download data for example
download_dataset(
    BASE_API_URL,
    DATA_FOLDER,
    files=[
        "BrainMesh_ICBM152.lh.curv",
        "xd.mz3",
        "yd.mz3",
        "zd.mz3",
        "BrainMesh_ICBM152.lh.mz3",
    ],
)
BrainMesh_ICBM152.lh.curv already exists.
xd.mz3 already exists.
yd.mz3 already exists.
zd.mz3 already exists.
BrainMesh_ICBM152.lh.mz3 already exists.
Dataset downloaded successfully to images.
In [2]:
import ipywidgets as widgets

import ipyniivue

# Initialize NiiVue
nv = ipyniivue.NiiVue(
    show_3d_crosshair=True,
    back_color=[0.7, 0.7, 0.7, 1],
    is_colorbar=True,
    slice_type=ipyniivue.SliceType.RENDER,
)

# Layer 1: Curvature
layer1 = ipyniivue.MeshLayer(
    path=DATA_FOLDER / "BrainMesh_ICBM152.lh.curv",
    colormap="gray",
    colormap_negative="",
    cal_min=0.3,
    cal_max=0.5,
    opacity=0.7,
)
layer1.colorbar_visible = False

# Layer 2: XD
layer2 = ipyniivue.MeshLayer(
    path=DATA_FOLDER / "xd.mz3",
    colormap="red",
    colormap_negative="",
    cal_min=2.5,
    cal_max=4.5,
)
layer2.colormap_type = ipyniivue.ColormapType.ZERO_TO_MAX_TRANSLUCENT_BELOW_MIN

# Layer 3: YD
layer3 = ipyniivue.MeshLayer(
    path=DATA_FOLDER / "yd.mz3",
    colormap="green",
    colormap_negative="",
    cal_min=1.5,
    cal_max=3.5,
)
layer3.colormap_type = ipyniivue.ColormapType.ZERO_TO_MAX_TRANSLUCENT_BELOW_MIN

# Layer 4: ZD
layer4 = ipyniivue.MeshLayer(
    path=DATA_FOLDER / "zd.mz3",
    colormap="blue",
    colormap_negative="",
    cal_min=1.5,
    cal_max=3.5,
)
layer4.colormap_type = ipyniivue.ColormapType.ZERO_TO_MAX_TRANSLUCENT_BELOW_MIN

nv.load_meshes(
    [
        {
            "path": DATA_FOLDER / "BrainMesh_ICBM152.lh.mz3",
            "layers": [layer1, layer2, layer3, layer4],
        }
    ]
)

nv.set_clip_plane(-0.1, 270, 0)

# --- UI Controls ---

# 1. Additive Blend Checkbox
additive_check = widgets.Checkbox(value=True, description="Additive")


def on_additive_change(change):
    """Handle additive change."""
    if not nv.meshes:
        return
    mesh = nv.meshes[0]
    # Indices 1, 2, 3 correspond to layers 2, 3, 4
    for i in range(1, 4):
        nv.set_mesh_layer_property(mesh.id, i, "is_additive_blend", change["new"])


additive_check.observe(on_additive_change, names="value")


# 2. Opacity Slider
opacity_slider = widgets.IntSlider(min=0, max=10, value=10, description="Opacity")


def on_opacity_change(change):
    """Handle opacity change."""
    if not nv.meshes:
        return
    mesh_id = nv.meshes[0].id
    val = change["new"] * 0.1
    for i in range(1, 4):
        nv.set_mesh_layer_property(mesh_id, i, "opacity", val)


opacity_slider.observe(on_opacity_change, names="value")


# 3. Red Slider (Left)
red_slider = widgets.IntSlider(min=0, max=5, value=2, description="RedLeft")


def on_red_change(change):
    """Handle red slider change."""
    if not nv.meshes:
        return
    mesh_id = nv.meshes[0].id
    val = change["new"]
    nv.set_mesh_layer_property(mesh_id, 1, "cal_min", val + 0.5)
    nv.set_mesh_layer_property(mesh_id, 1, "cal_max", val + 2.5)


red_slider.observe(on_red_change, names="value")


# 4. Green Slider (Anterior)
green_slider = widgets.IntSlider(min=0, max=5, value=1, description="GreenAnt")


def on_green_change(change):
    """Handle green slider change."""
    if not nv.meshes:
        return
    mesh_id = nv.meshes[0].id
    val = change["new"]
    nv.set_mesh_layer_property(mesh_id, 2, "cal_min", val + 0.5)
    nv.set_mesh_layer_property(mesh_id, 2, "cal_max", val + 2.5)


green_slider.observe(on_green_change, names="value")


# 5. Blue Slider (Superior)
blue_slider = widgets.IntSlider(min=0, max=5, value=1, description="BlueSup")


def on_blue_change(change):
    """Handle blue slider change."""
    if not nv.meshes:
        return
    mesh_id = nv.meshes[0].id
    val = change["new"]
    nv.set_mesh_layer_property(mesh_id, 3, "cal_min", val + 0.5)
    nv.set_mesh_layer_property(mesh_id, 3, "cal_max", val + 2.5)


blue_slider.observe(on_blue_change, names="value")


# 6. Shader Dropdown
shader_drop = widgets.Dropdown(
    options=["Edge", "Flat", "Matcap", "Matte", "Outline", "Phong", "Toon"],
    value="Matcap",
    description="Shader",
)


def on_shader_change(change):
    """Handle shader change."""
    if not nv.meshes:
        return
    mesh_id = nv.meshes[0].id
    nv.set_mesh_shader(mesh_id, change["new"])


shader_drop.observe(on_shader_change, names="value")


# --- Initial Setup Callback ---
@nv.on_mesh_loaded
def set_initial_props(m):
    """Apply all UI values to the mesh once loaded."""
    if nv.meshes:
        on_additive_change({"new": additive_check.value})
        on_opacity_change({"new": opacity_slider.value})
        on_red_change({"new": red_slider.value})
        on_green_change({"new": green_slider.value})
        on_blue_change({"new": blue_slider.value})
        on_shader_change({"new": shader_drop.value})


# Layout
ui = widgets.VBox(
    [
        widgets.HBox([additive_check, opacity_slider]),
        widgets.HBox([red_slider, green_slider, blue_slider]),
        shader_drop,
        nv,
    ]
)

ui
Out[2]: